﻿using System;
using System.Collections.Generic;
using System.Reflection;
using GameFramework.common;
using GameFramework.events;
using GameFramework.timer;
using UnityEngine;
using UnityEngine.UIElements;
using Timer = System.Timers.Timer;

namespace GameFramework.UI
{
    /// <summary>
    /// 视图生命周期：(【】包围的内容需要使用者来实现，即init,modelPrepared,beforeShow,afterShow，其他部分框架已经完成)
    /// 初始阶段：
    /// 1.【setRootElement】 来设置视图根节点
    /// 2.给根元素注册动画结束的事件 TransitionEndEvent
    /// 3.自动查找Element控件元素
    /// 4.注册 界面显示时，收到的数据准备就绪的监听器：
    ///    【modelPrepared】 此方法的逻辑需要使用者实现，一般为将初始数据填充到Element控件中
    /// 5.【init初始化方法】，使用者实现，一般为初始一次的逻辑，这个初始化操作只会在view对象设置根元素时执行一次
    ///
    /// 显示阶段：
    /// 6.【通过UIManager.Instance.show()来显示视图】使用者操作
    /// 7.show方法逻辑：调用reuse方法来激活pause禁用的操作
    /// 8.show方法逻辑：调用beforeShow方法来执行显示前的逻辑,【beforeShow需要使用者按需实现】
    /// 9.show方法逻辑：移除延时显示的定时器，每个界面默认延时0.1秒显示，因为考虑到uielement第一帧初始化后如果添加动画类名，是不生效的，因为第一帧检测不出前后属性的不同，就不执行动画
    /// 10.show方法逻辑：添加延时执行的定时器
    /// 12.定时器里的逻辑：显示元素
    /// 13.如果有动画(默认有)，则添加动画类(这个类名是固定的，效果使用者在uss中自己定义)，
    /// 14.将显示的根元素移动到最前面(即根元素子界面的末尾)
    /// 15.发出显示事件，让监听此界面显示的逻辑执行，一般为界面的数据类监听(MVP中的M)，来回调前面注册的modelPrepared方法，并将数据传递给此方法
    /// 16.【调用afterShow方法来执行显示后的逻辑】
    ///
    /// 隐藏阶段
    /// 17.【调用UIManager.Instance.hide()来隐藏视图】
    /// 18.hide方法里的逻辑：先执行beforeHide的逻辑。【beforeHide需要使用者实现】
    /// 19.hide方法里的逻辑：取消UIElement元素绑定的事件，隐藏根节点
    /// TODO 需要发布界面关闭的消息么
    /// 20.hide方法里的逻辑：执行afterHide的逻辑。【afterHide需要使用者实现】
    /// </summary>
    [System.Serializable]
    public  class BaseView:IView
    {
        protected VisualElement _root;
        public string sceneViewManagerName;
        protected bool m_HideOnAwake = true;
        protected bool m_UseTransition = true;
        protected EventRegistry m_EventRegistry;
        protected float m_TransitionDelay = 0.1f;
        protected int m_TransitionTimerId;

        public const string k_VisibleClass = "screen-visible";
        public const string k_HiddenClass = "screen-hidden";

        public VisualElement RootElement
        {
            get
            {
                return _root;
            }
        }

        // If the m_ParentElement is fading off, hide it once the USS transition is complete
        private void HideTrasitionEnd(TransitionEndEvent evt)
        {
            if (evt.target == _root && _root.ClassListContains(k_HiddenClass))
            {
                HideImmediately();
            }
        }
        public void HideImmediately()
        {
            _root.style.display = DisplayStyle.None;
        }
        public void ShowImmediately()
        {
            _root.style.display = DisplayStyle.Flex;
        }

        protected void elementRegisterCallBack<TEvent>(VisualElement element, Action<TEvent> callback) where TEvent : EventBase<TEvent>, new()
        {
            m_EventRegistry.RegisterCallback(element,callback);
        }

        public void setRootElement(VisualElement rootElement)
        {
            
            _root = rootElement ?? throw new ArgumentNullException(nameof(rootElement));
            if (m_HideOnAwake)
            {
                HideImmediately();
            }
            m_EventRegistry = new EventRegistry();
            m_EventRegistry.RegisterCallback<TransitionEndEvent>(_root, HideTrasitionEnd);
            bindableElement();
            MVPEventManager.Instance.onViewModelPreparedListener(this.GetType(),data=>modelPrepared(data));
            init();
        }

        protected virtual void modelPrepared(object data)
        {
            
        }

        /// <summary>
        /// 根据注解绑定控件
        /// </summary>
        private void bindableElement()
        {
            FieldInfo[] infos = GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance|BindingFlags.Public);
            foreach (FieldInfo fieldInfo in infos)
            {
                UIBind uiBind = fieldInfo.GetCustomAttribute<UIBind>();

                if (uiBind == null)
                {
                    continue;
                }

                string name = uiBind.Name;
                string className = uiBind.ClassName;
                if ((name == null && className == null))
                {
                    Debug.LogError($"类： {GetType().Name} 字段： {fieldInfo.Name} 特性UIBind未设置Name或ClassName字段！绑定失败！");
                    continue;
                }

                if (name != null)
                {
                    name = name.Trim();
                }

                if (className != null)
                {
                    className = className.Trim();
                }

                if ((name == null && className.Length == 0) || (className == null && name.Length == 0))
                {
                    Debug.LogError($"类： {GetType().Name} 字段： {fieldInfo.Name} 特性UIBind的Name或ClassName应该至少有一个不为空，绑定失败！");
                    continue;
                }

                List<string> classNames = new List<string>();
                if (className != null && className.Length > 0)
                {
                    string[] strings = className.Split(" ");
                    
                    foreach (var s in strings)
                    {
                        if (s.Trim().Length > 0)
                        {
                            classNames.Add(s.Trim());
                        }
                    }
                }
                
                //TODO
                // 1.如果字段类型是数组或list类型，则查找所有满足条件的
                // 2.如果是单个控件，则需要检查查找到的是否是一个，报警告
                VisualElement visualElement = this._root.Q<VisualElement>(name,classNames.Count>0?classNames.ToArray():null);
                // Debug.Log(visualElement);
                if (visualElement == null)
                {
                    Debug.LogError($"类： {GetType().Name} 字段： {fieldInfo.Name} 特性UIBind无法根据Name：{name} 或className: {className} 查找到对应元素！绑定失败！");
                    continue;
                }
                
                fieldInfo.SetValue(this,visualElement);
            }
        }

        public virtual void init()
        {
        }
        

        public virtual void show()
        {
            //TODO 从module中拿取数据进行填充
            // UIManager.Instance.RootElement.Add(_root);
            reUse();
            beforeShow();
            TimerManager.Instance.removeTimer(m_TransitionTimerId);
            m_TransitionTimerId = TimerManager.Instance.schedule(timer => ShowWithDelay(), m_TransitionDelay);
        }
        public  virtual void beforeShow()
        {
            
        }
        public virtual void afterShow()
        {
        }

        private void ShowWithDelay()
        {
            _root.style.display = DisplayStyle.Flex;

            if (m_UseTransition)
            {
                Debug.Log("show view:"+this.GetType().Name);
                _root.AddToClassList(k_VisibleClass); // Add visible class
                _root.BringToFront();
                _root.RemoveFromClassList(k_HiddenClass); // Remove hidden class
            }
            MVPEventManager.Instance.onViewShow(this.GetType());
            afterShow();
        }

        public virtual void pause()
        {
            Debug.Log("pause:"+this.GetType().Name);
            //停止响应UI事件
            this._root.pickingMode = PickingMode.Ignore;
        }

        public virtual void reUse()
        {
            // Debug.Log("reUse:"+this.GetType().Name);
            this._root.pickingMode = PickingMode.Position;
        }

        public virtual void beforeHide()
        {
            
        }

        public virtual  void hide()
        {
            // UIManager.Instance.RootElement.Remove(_root);
            m_EventRegistry.Dispose();
            this._root.style.display = DisplayStyle.None;
            //发布隐藏事件
        }
        public virtual void afterHide()
        {
            
        }
    }
}